/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

use ohmw_core::bincode::{Decode, DefaultDecoder, DefaultDecoderError, DefaultEncoder, DefaultEncoderError, Encode};
use ohmw_dora::node::DoraNodeContext;

pub enum Node {
    Dora(DoraNodeContext),
}

#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum NodeKind {
    Dora,
    ROS,
    ROS2,
}

#[derive(Debug, thiserror::Error)]
pub enum NodeError {
    #[error(transparent)]
    DoraError(#[from] eyre::Error),
    #[error(transparent)]
    EncodeError(#[from] DefaultEncoderError),
    #[error(transparent)]
    DecodeError(#[from] DefaultDecoderError),
}

impl Node {
    pub fn new(node_path: &str, kind: NodeKind) -> Result<Self, NodeError> {
        match kind {
            NodeKind::Dora => Ok(Node::Dora(DoraNodeContext::new(node_path)?)),
            NodeKind::ROS => todo!(),
            NodeKind::ROS2 => todo!(),
        }
    }

    pub fn send(&mut self, path: &str, data: &[u8]) -> Result<(), NodeError> {
        match self {
            Node::Dora(dora_node_context) => Ok(dora_node_context.send(path, data)?),
        }
    }

    pub fn recv(&mut self, path: &str, timeout: u32) -> Result<Vec<u8>, NodeError> {
        match self {
            Node::Dora(dora_node_context) => Ok(dora_node_context.recv(path, timeout)?),
        }
    }

    pub fn on_recv<F>(&mut self, path: &str, callback: F) -> Result<(), NodeError>
    where F: Fn(&mut [u8]) + Send + 'static
    {
        match self {
            Node::Dora(dora_node_context) => Ok(dora_node_context.on_recv(path, callback)?),
        }
    }

    pub fn send_msg<T: Encode>(&mut self, path: &str, msg: T) -> Result<(), NodeError> {
        let mut buf = Vec::new();
        msg.encode(&mut DefaultEncoder::new(), &mut buf)?;
        self.send(path,buf.as_slice())?;
        Ok(())
    }

    pub fn recv_msg<T: Decode>(&mut self, path: &str, timeout: u32) -> Result<T, NodeError> {
        let data = self.recv(path, timeout)?;
        Ok(T::decode(&mut DefaultDecoder::new(), data.as_slice())?)
    }

    pub fn on_recv_msg<T: Decode, F>(&mut self, path: &str, callback: F) -> Result<(), NodeError>
    where F: Fn(T) + Send + 'static
    {
        let callback = move |data: &mut [u8]| {
            match T::decode(&mut DefaultDecoder::new(), data) {
                Ok(msg) => callback(msg),
                Err(err) => tracing::error!("Error decoding message: {}", err),
            }
        };
        self.on_recv(path, callback)
    }

    pub fn channel(&mut self, node_path: &str) -> Result<(), NodeError> {
        todo!()
    }
}
